package com.ruoyi.optimization.controller;


import com.alibaba.fastjson2.JSON;
import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.io.source.ByteArrayOutputStream;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.layout.font.FontProvider;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.optimization.common.Individual;
import com.ruoyi.optimization.common.MaterialOptimization;
import com.ruoyi.optimization.common.MaterialReq;
import com.ruoyi.optimization.common.PartsReq;
import com.ruoyi.optimization.domain.*;
import com.ruoyi.optimization.service.IOptimizationRecordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/optimization")
public class optimizationController {

    @GetMapping("/test")
    public String test(){
        return "Hello World";
    }

    @Autowired
    private TemplateEngine templateEngine;

    @Autowired
    private IOptimizationRecordService optimizationRecordService;


    // 优化
    @RequestMapping(value = "optimize", method = RequestMethod.POST)
    public optimizeRes optimize(@RequestBody OptimizeRequest request,@RequestHeader(value = "Authorization",required = false) String authorization) {
        ArrayList<MaterialReq> materials = request.getMaterials();
        ArrayList<PartsReq> parts = request.getParts();
        long start = System.currentTimeMillis();
        Individual individual = MaterialOptimization.geneticAlgorithm(materials, parts);
        long end = System.currentTimeMillis();
        if (individual == null){
            return null;
        }
        System.out.println("耗时: " + (end-start) + "利用率："+ individual.getFitness());
        if (individual != null){
            individual.getMaterialMap().forEach((key, value) -> {
                System.out.println("key: " + key + " 使用数量: " + value.size());
                value.forEach(element1 -> {
                    System.out.println("partLength: " + element1.getLength() + " parts: " + element1.getParts() + "remaing:"+element1.getRemaining());
                });
            });
        }
        ArrayList<MaterialRes> objects = new ArrayList<>();
        // 原材料使用情况
        HashMap<String, Integer> materialCount = new HashMap<>();
        HashMap<String, Integer> partsCount = new HashMap<>();
        HashMap<String,String> lengthToMark = new HashMap<>();
        parts.forEach(partRes -> {
            lengthToMark.put(String.valueOf(partRes.getLength()), partRes.getMark());
        });

        HashMap<String, MaterialRes> materialMap = new HashMap<>();
        individual.getMaterialMap().forEach((key,value)->{
            if (!value.isEmpty()){
                materialCount.put(String.valueOf(value.get(0).getLength()), value.size());
            }
            value.forEach(element -> {
                String join = element.getLength()+"-"+String.join(",", element.getParts().stream().sorted().map(String::valueOf).collect(Collectors.toList()));
                MaterialRes materials1 = materialMap.get(join);
                if (materials1 == null){
                    MaterialRes materialRes = new MaterialRes();
                    materialRes.setLength(element.getLength());
                    materialRes.setRemaining(element.getRemaining());
                    materialRes.setCount(1);
                    materialRes.setParts(new ArrayList<>());
                    Map<Integer, Long> collect = element.getParts().stream().collect(Collectors.groupingBy(Integer::intValue, Collectors.counting()));
                    collect.forEach((k,v)->{
                        materialRes.getParts().add(new PartRes(lengthToMark.get(String.valueOf(k)), k,v.intValue()));
                    });
                    materialMap.put(join, materialRes);
                }else{
                    materials1.setCount(materials1.getCount()+1);
                }

            });
        });

        // 整理一根材料中数相同长度零件最汇总操作
        materialMap.forEach((k,v)->{
            objects.add(v);
        });

        individual.getParts().forEach(element -> {
            partsCount.put(String.valueOf(element.getLength()), element.getCount());
        });
        optimizeRes res = new optimizeRes();
        res.setFitness(individual.getFitness());
        res.setMaterial(objects);
        res.setMaterialLengthToCount(materialCount);
        res.setPartLengthToCount(partsCount);
        Double collect = objects.stream().map(element -> element.getRemaining()).collect(Collectors.summingDouble(Integer::intValue));
        res.setLoss(collect);
        // 存储优化记录
        OptimizationRecord optimizationRecord = new OptimizationRecord();

        optimizationRecord.setOperIp(IpUtils.getIpAddr());
        String jsonString = JSON.toJSONString(res);
        optimizationRecord.setData(jsonString);
        optimizationRecord.setFitness(new BigDecimal(res.getFitness().toString()));
        optimizationRecord.setTitle(DateUtils.getTime());
        optimizationRecordService.insertOptimizationRecord(optimizationRecord,authorization);
        res.setId(optimizationRecord.getId());
        return res;
    }
    // 新增生成文件的方法
    @RequestMapping(value = "generateFile", method = RequestMethod.POST)
    public ResponseEntity<String> generateFile(@RequestBody optimizeRes res) {
        String reportContent = generateReport(res);
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=optimization_report.txt")
                .contentType(MediaType.TEXT_PLAIN)
                .body(reportContent);
    }

    @RequestMapping(value = "generatePdf", method = RequestMethod.POST)
    public ResponseEntity<byte[]> exportPdf(@RequestBody optimizeRes res) throws Exception {
        String htmlContent = generateHtmlFromTemplate(res);

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        // 创建字体提供器并添加中文字体
        FontProvider fontProvider = new FontProvider();

        // 从资源流加载字体

//        String fontPath = Objects.requireNonNull(getClass().getResource("/static/fonts/STFANGSO.TTF")).getPath();
        String fontPath = "/usr/local/src/service/STFANGSO.TTF";
        PdfFont chineseFont = PdfFontFactory.createFont(fontPath, PdfEncodings.UTF8, PdfFontFactory.EmbeddingStrategy.FORCE_EMBEDDED);
        fontProvider.addFont(chineseFont.getFontProgram());

        // 设置 ConverterProperties
        ConverterProperties converterProperties = new ConverterProperties();
        converterProperties.setFontProvider(fontProvider);

        // 转换 HTML 到 PDF
        HtmlConverter.convertToPdf(htmlContent, outputStream, converterProperties);

        byte[] pdfBytes = outputStream.toByteArray();

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_PDF);
        headers.setContentDispositionFormData("attachment", "optimization_report.pdf");

        return ResponseEntity.ok().headers(headers).body(pdfBytes);
    }

    private String generateHtmlFromTemplate(optimizeRes res) {
        Context context = new Context();
        context.setVariable("res", res);
        return templateEngine.process("report_template", context);
    }
//    // 新增生成文件的方法
//    @RequestMapping(value = "generateFile", method = RequestMethod.POST)
//    public String generateFile(@RequestBody optimizeRes res) {
//        try {
//            FileWriter writer = new FileWriter("optimization_report.txt");
//            writer.write("");
//            writer.write(generateReport(res));
//            writer.close();
//            return "File generated successfully";
//        } catch (IOException e) {
//            e.printStackTrace();
//            return "Failed to generate file";
//        }
//    }

    // 新增生成报告的方法
    private String generateReport(optimizeRes res) {
        StringBuilder report = new StringBuilder();
        report.append("方案汇总信息：\n\n");
        report.append("原材料总数：").append(res.getMaterial().size()).append("     ");
        report.append("损耗统计：").append(res.getLoss().intValue()).append("     ");
        report.append("总体利用率：").append(String.format("%.2f", res.getFitness() * 100)).append("%\n\n");

        Map<String, Integer> materialCount = res.getMaterialLengthToCount();
        Map<String, Integer> partsCount = res.getPartLengthToCount();
        report.append("原料规格： ");
        for (String length : materialCount.keySet()) {
            report.append(length).append("x").append(materialCount.get(length)).append(" ");
        }
        report.append("\n\n下料规格： ");
        for (String length : partsCount.keySet()) {
            report.append(length).append("x").append(partsCount.get(length)).append(" ");
        }
        report.append("\n");
        report.append("\n");
        for (int i = 0; i < res.getMaterial().size(); i++) {
            MaterialRes materialRes = res.getMaterial().get(i);
            String partsInfo = (i+1)+"、"+materialRes.getParts().stream().map(j->{
                return j.getMark()+")"+j.getLength()+"x"+j.getCount();
            }).collect(Collectors.joining("   "));
            String materialInfo = "需要"+materialRes.getLength()+"材料 "+materialRes.getCount()+"根 余"+materialRes.getRemaining().intValue();
            int totalWidth = 85;

            String formatted = String.format("%-" + totalWidth + "s", partsInfo + String.format("%" + (totalWidth - partsInfo.length()*2) + "s", materialInfo));
            report.append(formatted);
            report.append("\nˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉ\n");
        }
        return report.toString();
    }
}